
Final Fantasy VI
Bank C3 Compendium

By Novalia Spirit
Contact: novaliaspirit (AIM, Hotmail)

Released on July 11, 2016
Last updated on October 11, 2016


Table of contents
1. Project description
2. Disassembly notes
  2.1 General notes
  2.2 Limitations and warnings
  2.3 Optimized disassembly
  2.4 Corrected coding mistakes
  2.5 Optimizations ruled out
  2.6 Menu variables freed
  2.7 Ending variables freed
  2.8 SRAM variables freed
  2.9 Terminology
3. Memory map notes
4. Assembler notes
  4.1 Compilation instructions
  4.2 Noteworthy bugs
5. Acknowledgements
6. Legal notice


###############################################################################
                            1. Project description
###############################################################################

A set of fully commented disassemblies and complementary documents pertaining
to bank C3 from the SNES and SFC versions of Final Fantasy VI. The bank handles
all of the field menus, as well as ending scenes that are beyond the scope of
the event program.

The archive includes:

  An optimized disassembly of bank C3 that saves more than 14,200 bytes while
   retaining the simplicity and flexibility of the original code.

  An optimized disassembly of bank C3 that seeks to maximize free space
   without regard for practicality. As it stands, the bank is reduced by
   26,054 bytes, and is consequently 42.3% smaller.

  An alternative version of the heavily optimized disassembly that sacrifices
   an insignificant amount of space in favor of definitions for global text
   arrays.

  A reassemblable, unmodified disassembly of bank C3. Recommended for
   projects of limited scope or for testing purposes. Useful for reverting
   modifications, for locating data, or for determining loop points or entry
   points.

  A basic disassembly of bank C3. The main purpose of this document is to
   provide the address of every instruction in an unmodified game.

  A basic disassembly of bank D4, which acts as an extension of bank C3. A
   reassemblable, unmodified version is also available.

  A basic disassembly of bank C2, a hodgepodge in terms of content, purged of
   code and data irrelevant to bank C3.

  A complete memory map, one for the menus and one for the ending, that
   details the structure of both RAM and VRAM.

  Scripts, tools, character tables, and define-type directives for compilation
   purposes.

  A folder that contains two copies of bank C3, one for each console, that
   have been specially formatted for side-by-side comparison. Also included is
   a list of noteworthy version differences.

  Release notes that include additional information such as abbreviations and
   compilation instructions. A list of bug findings as well as content that has
   been cut may be added in the future.

Given the abundance of memory available, the implementation of labels for RAM
addresses was dismissed as impractical. In the same vein, the size of every
instruction is not explicitly specified at this time.


###############################################################################
                             2. Disassembly notes
###############################################################################

General notes:
  A tabulation is expected to correspond to eight spaces.
  Functions called during an NMI are marked with "(NMI)."
  Select is not listed but is interpreted as R (excludes $04 and $05).
  Positions and slot numbers are counted from one and upward, not from zero.
  SFC: Strings with diacritics must be positioned a row higher than intended.

Limitations and warnings:
  Item descriptions that exceed 64 characters will corrupt shop prices.
  Rare item count will likely be inaccurate if no empty slot (fix: C3/839A).
  Merit Award effect is automatically applied to Guest Slot 2 (see C3/9C5F).
  Gear data menu can only display up to six elements per category (C3/8921).
  Target of the 'Optimize Gear' event command must be in the active party.
  Palette of Locke's portrait in Lineup menu is affected by his disguise.
  Dance list retains last palette used; normally that of "Dance" in menu list.
  C3/7173 lacks TDC (forced member check for Lineup menu choice 1).
  The decompression routine in bank C2 changes the WRAM bank.

Optimized disassembly:
  This has not been tested on hardware.
  Bug fixes have not been implemented; such a decision is left to the user.
   However, two minor sprite position bugs had to be fixed as a result of an
   optimization. One affects the scrollbar in the Espers menu, while the other
   concerns one of the playing cards during Setzer's ending scene. Another bug
   that was fixed for the same reason is the fact that key presses are ignored
   during the prologue in certain situations. Likewise, I had to fix a bug that
   caused the game to be saved to the wrong save slot while moving the cursor.
   I also ended up fixing the timing for the glowing eye in the helmet during
   Gogo's ending scene, and the NMI-based variant of the "Equip Anything" bug.
   Some of these bugs are only fixed in the heavily optimized disassembly.
  The transparent color at C3/10F4 must be kept for the final airship scene.
  Variables $B7-$C2 now reflect the order of register addresses.


The following lists are for the heavily optimized disassembly.

Corrected coding mistakes:
  Three names were missing in the special thanks as a consequence of a
   miscalculated string count in the comments. To fix this manually, change
   "BEQ credx6b" to "BEQ credx9" at C3D928. (Oct. 11, 2016)
  Item menu failed to delete description after returning from item usage menu
   because of a stock shortage. See updated version of C3572A. (Oct. 11, 2016)
  Member swap animation always assumed the first choice was above the second.
   Change "ASL A" to "LDA #$18" at C32491 to fix this. (Oct. 11, 2016)
  Spacing between status icons was too wide. Change ADC #$10 to ADC #$0A
   at C3628B. (Oct. 11, 2016)
  Inconsequential: "ASL A, BEQ" -> "ASL A, BPL" at C37701. (Oct. 11, 2016)

Optimizations ruled out (vastly incomplete):
  Reorder entry points to remove JMP C3001B. Requires editing other banks.
  Switch code in D4 with data in C3, and optimize the code accordingly.
  #$FFFF -> $02 (always holds this value except in main menu on world map).
  C3/69BA: Could drop pointer tables and simply add Y to X before looping.
  Append two-dot leader to some or all stat names (SFC does so in some cases).
  Adjust tilemap pointers to remove any "INC A" after $E6. (for SFC diac.)
  Reorder button checks in various functions to allow for LSR or ASL.
  Might be able to free space and $46:4 by using timer $20 instead of $22.
  Freezing CGRAM may not serve any purpose other than saving cycles.
  Remove unused entries at C3/C406. Requires editing the event script.
  Setting direct page to 0 in the NMI function might be redundant.
  Do SEC in advance before calling any animation queue function.
  Setting the data bank register to 7E by default might save space.
  C3/10D4: Redirect to free space (high bit is unused so #$FFFF works).
  C3/10F4: Redirect to a matching sequence in the ROM.
  C3/02DB: STZ $0205 would have the same effect.
  Ones digit at C3/8854 and beyond is always zero.
  Clearing item quantities seems pointless.

Menu variables freed:
  $22 (Lineup)
  $28 (Lineup's Status menu)
  $2B, $2C
  $2F, $30
  $49, $4C (Lineup)
  $51, $52
  $57, $58
  $5A, $5B, $5D (Lineup)
  $5F (Espers menu)
  $64 (Status, Equip, Relic, Item, Cmd.Set)
  $65, $79 (Status)
  $79-$7B, $8D-$8F, $90 (Lineup)
  $97, $98 (zeroed in D4)
  $99 (Relic, Lineup)
  $9A (Lineup)
  $9E, $9F (Save menu)
  $B0, $B1 (item usage menu)
  $C9 (Equip)
  $CB, $CC
  $D1
  $0201 (joypad decoding in battle; must delete C1/1B8F)
  $020F
  $0213-$021A, $0220-$0223, $0229, $022A
  $1D50-$1D53
  $1DC7, $1DC8
  $3040-$3048 (Equip, Relic)
  $374A,X
  $9DB9-$9DE4 (Lineup)
  $9E09-$9E19 (gear data menu)
  $9E51-$9E7C (Lineup)
  $AA89-$AA8C

Ending variables freed:
  $2B, $2C
  $2F, $30
  $4D-$50
  $53, $54
  $58, $59
  $60, $61 (zeroed in D4)
  $374A,X

SRAM variables freed:
  $307FFE, $307FFF (SRAM marker)


Terminology:
  ...           Pointless code or data
  2H            Two-handed
  2Rx1B         2 registers, 1 byte each
  Adr           Address
  Alias         Actor name defined by player
  Anim          Animation
  b1            Bit 1
  B1            Byte 1
  Bar           Scrollbar
  BG1a          Background 1, tilemap a
  Blinker       Blinking hand cursor
  Box           Text box (menu window)
  bpp           Bits per pixel
  BRT           Brightness
  BWD           Backward
  C-            Clear Carry flag
  CCW           Counterclockwise
  Cfg           Config
  CH1           Channel 1
  Char          Character
  Cmd           Command
  Col           Column
  Coord         Coordinate
  CW            Clockwise
  D-Pad         Directional pad
  DB            Data bank
  Desc          Description
  Desig         Designation
  DP            Direct page
  Draw          Build tilemap for
  Dst           Destination
  Elem          Element
  Fn            Function
  Fract         Fractional
  Frontview     Facing the camera
  FWD           Forward
  FWF           Fixed-width font
  GFX           Graphics
  H             Horizontal
  HB            High byte
  Hi-fork       Fork above main function
  Indir         Indirect
  Init          Initialize
  INT           Interrupt
  L             Left
  LB            Low byte
  Loc           Location
  LSB           Least significant bit
  M7            Mode 7
  MB            Middle byte
  Min           Minimum
  MS            Main screen
  MSB           Most significant bit
  Msg           Message
  MT            Multitarget
  Num           Number
  OBJ           Object
  Optimzn       Optimization
  Pad           Joypad
  Pal           Palette
  Prio          Priority
  PS            Processor status
  Ptr           Pointer
  Px            Pixel
  Qty           Quantity
  R             Right
  Rearview      Viewed from the back
  Rel           Relative
  SFC           Super Famicom (version)
  SFX           Sound effects
  Sideview      Viewed from the side
  Skin          Wallpaper
  Spd           Speed
  Specs         Specifics
  Src           Source
  ST            Single target
  Stock         Inventory
  Sub           Subtract
  Sub:          Function in a function
  Tbl           Table
  Upload        Transfer to VRAM
  User          Player
  V             Vertical
  V1            Version 1
  Var           Variable
  Vol           Volume
  VWF           Variable-width font
  Win           Window
  WIP           Work in progress
  WR            Write


###############################################################################
                              3. Memory map notes
###############################################################################

  Unlisted flags are unused.
  An unspecified condition usually implies "if nonzero."
  A vertical bar denotes an array. Refer to the next line for the range.
  Alternate purposes for $00-$FF in Lineup menu were omitted for readability.
  Some variables may serve a different purpose in the Super Famicom version.
  $11A0 only covers actor data. Refer to bank C2 doc for alternate purposes.


###############################################################################
                              4. Assembler notes
###############################################################################

Compilation instructions (SNES):
1. Download Asar (1.35): http://www.romhacking.net/utilities/964
2. Extract asar.exe to a new folder.
3. Copy the .asm disassembly of your choice to the folder.
4. Copy ff6_bank_c3.tbl and ff6_bank_c3_defs.asm to the folder.
5. Copy a clean dump of the SNES ROM (1.0 or 1.1) to the folder.
6. Change its extension to .sfc if the ROM is headerless, otherwise use .smc.
7a. Execute asar.exe and follow the program's instructions.
7b. Execute compile.bat (see step 6 below to define file names).

Compilation instructions (SFC):
1. Extract the "sfc" folder from the archive.
2. Download Asar (1.35): http://www.romhacking.net/utilities/964
3. Extract asar.exe to the "bin" subdirectory.
4. Copy a clean dump of the SFC ROM to the "sfc" folder.
5. Change its extension to .sfc if the ROM is headerless, otherwise use .smc.
6. Open "compile.bat" in a text editor and rename "ff6_bank_c3j_opti.asm" and
   "ff6j.smc" in the code if need be. Both names must not contain spaces.
7. Execute compile.bat after applying the changes.

Open "charset.awk" in a text editor to consult or modify the character encoding
for strings enclosed in vertical bars, but keep in mind that substitutions are
not simultaneous.

Consider removing both "del" commands in the batch script to preserve the
temporary files; their file size provides an alarm for the corruption issue
described below, as making a mistake while modifying one of the scripts may
lead to a blank disasssembly.

Finally, be aware that Notepad adds a header (BOM) to UTF documents, which
may cause some issues.


Noteworthy bugs:

  From my experience, Asar will silently fail to convert text preceded by a
   label and four or more spaces, unless followed by a hex value, such as
   that of the terminator. As a workaround for the issue, a colon can be added
   to the indentation, as was done at C3/5CF7 in the vanilla SNES disassembly.

  If the very last instruction in bank C3 would be written to C4/0000, which
   is protected by the warnpc directive, assembling will abort as expected, but
   the console will return an "invalid command" error instead of warning about
   the crossed boundary.

  If a string contains a character that is missing from the .tbl document, a
   random hex value will be written to the ROM without notice.

  Asar updates the checksum and its complement at C0/FFDC, but the resulting
   values are incorrect.

  Asar accepts blank .asm files, but assumes a LoROM in the absence of the
   "hirom" directive. As a result, the checksum is written to adddress C0/7FDC,
   and consequently corrupts a portion of the field dialogue handler.


###############################################################################
                              5. Acknowledgements
###############################################################################

Anomie, for his register map.

Pelrun, for his disassembler, DisPel.

Geiger, for his debug builds of Snes9X.

Martin Korth, for the various data viewers in no$sns.

Assassin, for his bank C2 disassembly, which helped to identify a number of
battle variables for my partial disassembly of the bank.

The authors of the various tools included in the bin folder.


###############################################################################
                              6. Legal disclaimer
###############################################################################

The contents of the documents included in the archive cannot be reproduced
without the written consent of the author, unless for personal purposes.
Permission to distribute the archive and its contents is granted exclusively
to www.romhacking.net.

 2016 Jame Coban. All rights reserved.
